from fastapi import APIRouter, UploadFile, File, HTTPException, Body, Query
from fastapi.responses import StreamingResponse, JSONResponse
from typing import List
from urllib.parse import quote
import io
import zipfile
from app.utils import oss_service
from app.schemas import oss

oss_router = APIRouter(tags=["OSS文件相关"])

@oss_router.post("/upload", summary="上传文件", description="将文件上传到 OSS。")
async def upload_file(
    object_name: str = Query(..., description="OSS 中的对象名（文件名）"),
    file: UploadFile = File(..., description="要上传的文件")
):
    """
    上传文件到 OSS。
    """
    try:
        result = oss_service.upload_file(object_name, await file.read())
        return {"message": "Upload successful", "status": result.status}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.get("/download", summary="下载文件", description="从 OSS 下载文件。")
def download_file(object_name: str = Query(..., description="OSS 中的对象名（文件名）")):
    """
    下载 OSS 文件。
    """
    try:
        # 从 OSS 获取文件流
        file_stream = oss_service.download_file(object_name)
        
        # 对可能包含特殊字符的文件名进行 URL 编码
        encoded_filename = quote(object_name)
        
        # 设置 Content-Disposition 响应头
        headers = {
            # 用于指示文件下载，并指定文件名
            "Content-Disposition": f'attachment; filename="{object_name}"; filename*=UTF-8\'\'{encoded_filename}',
        }
        
        # 返回 StreamingResponse
        return StreamingResponse(file_stream, media_type="application/octet-stream", headers=headers)
    
    except Exception as e:
        # 如果文件下载失败，返回 404 错误
        raise HTTPException(status_code=404, detail=str(e))

@oss_router.get("/list", summary="列举文件", description="列出 OSS Bucket 中的所有文件。")
def list_files():
    """
    列出所有 OSS 文件。
    """
    try:
        files = oss_service.list_files()
        return JSONResponse(content={"files": files})
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.delete("/delete", response_model=oss.DeleteResponse, summary="删除文件", description="删除 OSS 中的单个文件。")
def delete_file(req: oss.DeleteRequest = Body(..., description="要删除的对象名")):
    """
    删除 OSS 单个文件。
    """
    try:
        result = oss_service.delete_file(req.object_name)
        return {"deleted": [req.object_name]}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.delete("/batch-delete", response_model=oss.DeleteResponse, summary="批量删除文件", description="批量删除 OSS 中的多个文件。")
def batch_delete_files(req: oss.BatchDeleteRequest = Body(..., description="要批量删除的对象名列表")):
    """
    批量删除 OSS 文件。
    """
    try:
        deleted = oss_service.batch_delete_files(req.object_names)
        return {"deleted": deleted}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.get("/meta", response_model=oss.ObjectMetaResponse, summary="获取文件元信息", description="获取 OSS 文件的元信息（如大小、修改时间等）。")
def get_object_meta(object_name: str = Query(..., description="OSS 中的对象名")):
    """
    获取 OSS 文件元信息。
    """
    try:
        meta = oss_service.get_object_metadata(object_name)
        return meta
    except Exception as e:
        raise HTTPException(status_code=404, detail=str(e))

@oss_router.get("/exists", response_model=oss.ExistsResponse, summary="检查文件是否存在", description="检查 OSS 文件是否存在。")
def check_exists(object_name: str = Query(..., description="OSS 中的对象名")):
    """
    检查 OSS 文件是否存在。
    """
    try:
        exists = oss_service.check_object_exists(object_name)
        return {"exists": exists}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.post("/set-acl", response_model=oss.ACLResponse, summary="设置文件权限", description="设置 OSS 文件的访问权限（ACL）。")
def set_acl(req: oss.ACLRequest = Body(..., description="对象名和权限类型")):
    """
    设置 OSS 文件 ACL 权限。
    """
    try:
        oss_service.set_object_acl(req.object_name, req.acl)
        return {"acl": req.acl}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.get("/get-acl", response_model=oss.ACLResponse, summary="获取文件权限", description="获取 OSS 文件的访问权限（ACL）。")
def get_acl(object_name: str = Query(..., description="OSS 中的对象名")):
    """
    获取 OSS 文件 ACL 权限。
    """
    try:
        acl = oss_service.get_object_acl(object_name)
        return {"acl": acl}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.post("/signed-url", response_model=oss.SignedUrlResponse, summary="生成签名URL", description="生成 OSS 文件的临时签名访问 URL。")
def signed_url(req: oss.SignedUrlRequest = Body(..., description="对象名和有效期")):
    """
    生成 OSS 文件的签名 URL。
    """
    try:
        url = oss_service.generate_signed_url(req.object_name, req.expires)
        return {"url": url}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.post("/copy-object", response_model=oss.CopyObjectResponse, summary="复制对象", description="复制 OSS 中的对象到新对象名。")
def copy_object(req: oss.CopyObjectRequest = Body(..., description="源对象名和目标对象名")):
    """
    复制 OSS 文件。
    """
    try:
        result = oss_service.copy_object(req.source_object_name, req.target_object_name)
        return {"status": result.status, "etag": result.etag}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@oss_router.post("/batch-upload", summary="批量上传文件", description="批量上传多个文件到 OSS。")
async def batch_upload(files: List[UploadFile] = File(..., description="要上传的文件列表")):
    """
    批量上传文件到 OSS。
    """
    results = []
    for file in files:
        object_name = file.filename
        try:
            oss_service.upload_file(object_name, await file.read())
            results.append({"file": object_name, "status": "success"})
        except Exception as e:
            results.append({"file": object_name, "status": "fail", "reason": str(e)})
    return {"results": results}

@oss_router.post("/batch-download", summary="批量下载文件", description="批量下载多个 OSS 文件并打包为 zip。")
def batch_download(object_names: List[str] = Body(..., description="要下载的 OSS 文件名列表")):
    """
    批量下载 OSS 文件并打包为 zip。
    """
    zip_buffer = io.BytesIO()
    with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
        for name in object_names:
            try:
                file_stream = oss_service.download_file(name)
                zip_file.writestr(name, file_stream.read())
            except Exception as e:
                continue  # 跳过下载失败的文件
    zip_buffer.seek(0)
    headers = {
        "Content-Disposition": "attachment; filename=batch_download.zip"
    }
    return StreamingResponse(zip_buffer, media_type="application/zip", headers=headers)

@oss_router.get("/download-all", summary="下载全部文件", description="将 Bucket 中所有文件打包为 zip 下载。")
def download_all_files():
    """
    下载 Bucket 中所有文件并打包为 zip。
    """
    files = oss_service.list_files()
    zip_buffer = io.BytesIO()
    with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
        for name in files:
            try:
                file_stream = oss_service.download_file(name)
                zip_file.writestr(name, file_stream.read())
            except Exception:
                continue  # 跳过下载失败的文件
    zip_buffer.seek(0)
    headers = {
        "Content-Disposition": "attachment; filename=all_files.zip"
    }
    return StreamingResponse(zip_buffer, media_type="application/zip", headers=headers)
